#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "../umlcore/PartialElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class ParameterableElement;
class TemplateBinding;
class TemplateSignature;

/// <summary>
/// TemplateableElement
/// A TemplateableElement is an Element that can optionally be defined as a template
/// and bound to other templates.
/// </summary>
class UMLMODEL_EXPORT TemplateableElement : public PartialElement {

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// isTemplate
    /// The query isTemplate() returns whether this TemplateableElement is actually a
    /// template.
    /// </summary>
    virtual bool isTemplate() const;

    /// <summary>
    /// parameterableElements
    /// The query parameterableElements() returns the set of ParameterableElements that
    /// may be used as the parameteredElements for a TemplateParameter of this
    /// TemplateableElement. By default, this set includes all the ownedElements.
    /// Subclasses may override this operation if they choose to restrict the set of
    /// ParameterableElements.
    /// </summary>
    virtual shared_ptr<vector<ParameterableElement>> parameterableElements() const;

public: // Properties
    /// <summary>
    /// ownedTemplateSignature getter
    /// The optional TemplateSignature specifying the formal TemplateParameters for this
    /// TemplateableElement. If a TemplateableElement has a TemplateSignature, then it
    /// is a template.
    /// </summary>
    shared_ptr<TemplateSignature> ownedTemplateSignature() const;

    /// <summary>
    /// ownedTemplateSignature setter
    /// The optional TemplateSignature specifying the formal TemplateParameters for this
    /// TemplateableElement. If a TemplateableElement has a TemplateSignature, then it
    /// is a template.
    /// </summary>
    void setOwnedTemplateSignature(shared_ptr<TemplateSignature> value);

    /// <summary>
    /// templateBindings getter
    /// The optional TemplateBindings from this TemplateableElement to one or more
    /// templates.
    /// </summary>
    vector<shared_ptr<TemplateBinding>>& templateBindings();

private: // Fields
    /// <summary>
    /// ownedTemplateSignature
    /// The optional TemplateSignature specifying the formal TemplateParameters for this
    /// TemplateableElement. If a TemplateableElement has a TemplateSignature, then it
    /// is a template.
    /// </summary>
    shared_ptr<TemplateSignature> ownedTemplateSignature_;

    /// <summary>
    /// templateBindings
    /// The optional TemplateBindings from this TemplateableElement to one or more
    /// templates.
    /// </summary>
    vector<shared_ptr<TemplateBinding>> templateBindings_;

};

} // namespace uml
